
def accepts(*types):
	def check_args(f):
		assert len(types) == f.func_code.co_argcount, 'type len: %d args len: %d' %(len(types), f.func_code.co_argcount)
		def new_f(*args, **kwds):
			for (a, t) in zip(args, types):
				assert isinstance(a, t), 'arg %r does not match %s' % (a, t)
			return f(*args, **kwds)
		new_f.func_name = f.func_name	# why?
		return new_f
	return check_args

def returns(rtype):
	def check_ret(f):
		def new_f(*args, **kwds):
			ret = f(*args, **kwds)
			assert isinstance(ret, rtype), 'return value %r does not match %s' %(ret, rtype)
			return ret
		new_f.func_name = f.func_name
		return new_f
	return check_ret

@returns((int, float))
@accepts(int, (int, float))
def func(arg1, arg2):
	return arg1 + arg2

if __name__ == '__main__':
	print func(1, 2.0)
	print func('1', '2')

